Fork me on GitHub
package cas.cs4tb3.mellowd.compiler;

import com.sun.media.sound.AudioSynthesizer;

import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Sequence;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * Created on 2016-04-20.
 */
public class WavIODelegate implements SequenceIODelegate {
    private static WavIODelegate instance = new WavIODelegate();

    public static WavIODelegate getInstance() {
        return instance;
    }

    private WavIODelegate() { }

    private static final float SAMPLE_RATE = 96000; //Hz
    private static final int SAMPLE_SIZE = 24; //bits per sample
    private static final int CHANNELS_MONO = 1;
    private static final int CHANNELS_STEREO = 2;
    private static final Map<String, Object> AUDIOSTREAM_PROPERTIES = new HashMap<>();
    static {
        AUDIOSTREAM_PROPERTIES.put("interpolation", "sinc");
        AUDIOSTREAM_PROPERTIES.put("max polyphony", "1024");
    }

    @Override
    public void save(Sequence sequence, File outFile) throws IOException {
        VirtualMIDIPlayer player = new VirtualMIDIPlayer(sequence);

        AudioSynthesizer synth;
        try {
            synth = (AudioSynthesizer) MidiSystem.getSynthesizer();
        } catch (MidiUnavailableException | ClassCastException e) {
            throw new IOException("Cannot open audio synth for virtual playback.", e);
        }
        AudioFormat format = new AudioFormat(SAMPLE_RATE, SAMPLE_SIZE, CHANNELS_STEREO, true, false);
        AudioInputStream stream;
        try {
            stream = synth.openStream(format, AUDIOSTREAM_PROPERTIES);
        } catch (MidiUnavailableException e) {
            throw new IOException("Cannot open audio synth for virtual playback. Reason: " + e.getLocalizedMessage(), e);
        }

Play Sequence into AudioSynthesizer Receiver.

        try {
            player.playTrackFor(synth.getReceiver());
        } catch (MidiUnavailableException e) {
            throw new IOException("Cannot play the track back to the receiver. Reason: " + e.getLocalizedMessage(), e);
        }

Calculate how long the WAV file needs to be. Add 40 so that the end of the track isnt chopped

        final long len = (long) (stream.getFormat().getFrameRate() * (player.getDuration() + 40));
        stream = new AudioInputStream(stream, stream.getFormat(), len);

Write WAVE file to disk.

        AudioSystem.write(stream, AudioFileFormat.Type.WAVE, outFile);

        synth.close();
    }

    @Override
    public String getExtension() {
        return ".wav";
    }
}
h